// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: hyuan

#include "coin2/exchange/coincheck/api_order/native_rest_async_asio_subscriber.h"

namespace coin2::exchange::coincheck::api_order {

void CoincheckRestAsyncAsioSubscriber::QueryCancelOrder(const std::string& order_id) {
  RestParams params;
  params.set_order_id(order_id);
  auto http_context = rest_client()->QueryOrderCancelStatus(params);
  if (!http_context) return;
  http_context->handler =
      std::bind(&CoincheckRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void CoincheckRestAsyncAsioSubscriber::QueryCancelOrders() {
  const std::set<std::string>& cancel_status_order_ids = rest_client()->GetCancelStatusOrderIds();
  for (const auto& order_id : cancel_status_order_ids) {
    QueryCancelOrder(order_id);
  }
}

void CoincheckRestAsyncAsioSubscriber::QueryBalance() {
  RestParams params;
  auto http_context = rest_client()->QueryAccountBalance();
  if (!http_context) return;
  http_context->handler =
      std::bind(&CoincheckRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void CoincheckRestAsyncAsioSubscriber::QueryOpenOrders() {
  auto http_context = rest_client()->QueryOpenOrders();
  if (!http_context) return;
  http_context->handler =
      std::bind(&CoincheckRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void CoincheckRestAsyncAsioSubscriber::QueryFills() {
  auto http_context = rest_client()->QueryFills();
  if (!http_context) return;
  http_context->handler =
      std::bind(&CoincheckRestAsyncAsioSubscriber::HandleQuery, this, std::placeholders::_1);
  http_driver_->PostAsyncContext(http_context);
}

void CoincheckRestAsyncAsioSubscriber::SubscribeAsync() {
  AddPeriodicTask(
      std::bind(&CoincheckRestAsyncAsioSubscriber::QueryBalance, this),
      config_.query_account_balance_period_sec(),
      "query_balance");

  AddPeriodicTask(
      std::bind(&CoincheckRestAsyncAsioSubscriber::QueryOpenOrders, this),
      config_.query_open_orders_period_sec(),
      "query_open_orders");

  AddPeriodicTask(
      std::bind(&CoincheckRestAsyncAsioSubscriber::QueryFills, this),
      config_.query_fill_period_sec(),
      "query_fills");

  AddPeriodicTask(
      std::bind(&CoincheckRestAsyncAsioSubscriber::QueryCancelOrders, this),
      config_.query_cancel_orders_period_sec(),
      "query_cancel_orders");

  mb_->Subscribe("coincheck/order_cancel_status_add", [this](const std::string&, void* data) {
    std::string* order_id = reinterpret_cast<std::string*>(data);
    rest_client()->AddCancelStatusOrderIds(*order_id);
    QueryCancelOrder(*order_id);
  });

  mb_->Subscribe("coincheck/order_cancel_status_del", [this](const std::string&, void* data) {
    std::string* order_id = reinterpret_cast<std::string*>(data);
    rest_client()->DelCancelStatusOrderIds(*order_id);
  });
}

}  // namespace coin2::exchange::coincheck::api_order
